import { get, delay } from './utils/http';
import { Parser } from './parser';
import { Storage } from './storage';
import { Novel } from './models/novel';
import { config } from './config';

export class NovelCrawler {
    private parser: Parser;
    private storage: Storage;
    private delayTime: number;

    constructor(storagePath: string = config.storage.basePath, delayTime: number = config.request.delayTime) {
        this.parser = new Parser();
        this.storage = new Storage(storagePath);
        this.delayTime = delayTime;
    }

    async crawlNovel(url: string, webSite: string): Promise<Novel> {
        console.log(`开始爬取小说: ${url}`);
        const html = await get(url);
        let novel = this.parser.parseNovelInfo(html, url, webSite);
        const site = config.sites[webSite as keyof typeof config.sites];
        if (site) {
            const chaptersUrl = site.getChaptersUrl();
            if (chaptersUrl) {
                console.log(`检测到章节列表URL: ${chaptersUrl}`);
                const chaptersHtml = await get(chaptersUrl);
                novel = this.parser.parseChapterList(chaptersHtml, chaptersUrl, novel, webSite);
            }
        }
        await this.storage.saveNovel(novel);
        await this.crawlChapters(novel, webSite);
        return novel;
    }

    private async crawlChapters(novel: Novel, webSite: string): Promise<void> {
        console.log(`开始爬取《${novel.title}》的章节，共${novel.chapterList.length}章`);
        for (let i = 0; i < novel.chapterList.length; i++) {
            const chapterUrl = novel.chapterList[i];
            try {
                await delay(this.delayTime);
                const html = await get(chapterUrl);
                const chapter = this.parser.parseChapter(html, chapterUrl, novel.url, i + 1, webSite);
                await this.storage.saveChapter(chapter, novel.title);
                console.log(`进度: ${i + 1}/${novel.chapterList.length}`);
            } catch (error) {
                console.error(`爬取章节失败: ${chapterUrl}`, error);
                await delay(this.delayTime * 3);
            }
        }
        console.log(`《${novel.title}》的所有章节爬取完成`);
    }
}